//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <core.h>
#include <mantle.h>
#include <init.h>

#if defined(_GNUC)
//
// The follow two symbols are define in kernel.ld
//
EXTERN_C UInt32 _StartUpEntryBegin;
EXTERN_C UInt32 _StartUpEntryEnd;

// USER_STARTUP_ENTRY_BASE had defined in asdef.h
#define USER_STARTUP_ENTRY_SIZE    ((UInt32)&_StartUpEntryEnd \
    - (UInt32)&_StartUpEntryBegin)
#endif

EXTERN_C void __UserStartUpEntry();

typedef struct {
    Boolean (STDCALL *pfnStartUpEntry)(
            PVoid  hDllHandle,
            UInt32   dwReason,
            PVoid   preserved);
    PVoid hDllHandle;
} structEntry_t;

#if defined(_GNUC)
DECL_SECTION(".startupentry") void UserStartUpEntry(
    structEntry_t *pEntry, UInt32 dwReason)
{
DECL_ASMENTRY(__UserStartUpEntry)
    ASM(
        "addiu  $29, $29, -0x20;"
        "sw     $4, 0x20($29);"
        "sw     $5, 0x24($29);"
    "__UserStartUpEntry_1:"
        "lw     $3, 0x20($29);"
        "lw     $4, 4($3);"
        "beq    $0, $4, __UserStartUpEntry_2;"
        "lw     $3, 0($3);"
        "lw     $5, 0x24($29);"
        "li     $6, 0;"
        "jalr   $3;"
        "lw     $2, 0x20($29);"
        "addiu  $2, $2, -0x8;"
        "sw     $2, 0x20($29);"
        "b      __UserStartUpEntry_1;"
    "__UserStartUpEntry_2:"
        // Call SysExitThread
        "li     $4, 0;"
        "li     $3, 1;"
        "li     $2, 0xb;"
        "syscall;");

    assert(0 && "UserEntry: have called the syscall");

//    while (pEntry->hDllHandle != NULL) {
//        (*pEntry->pfnStartUpEntry)(pEntry->hDllHandle, dwReason, NULL);
//        pEntry--;
//    }
}
#elif defined(_EVC)

#else
#(error unknown compiler)
#endif

EXTERN DECL_CODEINIT bool_t CDECL InitUserEntryTable()
{
    // Page table alredy init in proxy entry (../_marshal/proxyentry.cpp)
    //
    assert(0 != g_initPageDir[PAGEDIR_INDEX(USER_STARTUP_ENTRY_BASE)].uValue);

#if defined(_GNUC)
    assert(&_StartUpEntryBegin == (UInt32*)&UserStartUpEntry);

    memcpy((void*)USER_STARTUP_ENTRY_BASE, (void *)&__UserStartUpEntry,
        USER_STARTUP_ENTRY_SIZE);
#elif defined(_EVC)
    memcpy((void*)USER_STARTUP_ENTRY_BASE, (void *)&__UserStartUpEntry,
        0x100);
#else
#error unknown compiler
#endif

    FlushCache();

    return TRUE;
}
